package com.wendy.common.dao.mybatis.handler;

import com.wendy.common.core.constant.BaseDbType;
import com.wendy.common.core.json.jackson.JsonArrayList;
import com.wendy.common.core.json.jackson.PercentageObject;
import com.wendy.common.core.json.jackson.ToJsonObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @Author: ALEX WANG
 * @Date: 2020/3/24 9:43
 */
@MappedTypes(value = { PercentageObject.class, JsonArrayList.class, ToJsonObject.class})
public class BaseObjectTypeHandler<T extends BaseDbType>  extends BaseTypeHandler <T> {
    private Class<T> clazz;

    public BaseObjectTypeHandler(Class<T> clazz) {
        this.clazz = clazz;
    }
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (jdbcType == null) {
            ps.setObject(i, parameter.selectDbTypeValue());
        } else {
            ps.setObject(i, parameter.selectDbTypeValue(), jdbcType.TYPE_CODE);
        }
    }
    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        T t= null;
        try {
            t = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        String actualTypeName = getTypeName();
        if(StringUtils.equals(actualTypeName,Integer.class.getName())){
            t.addDbTypeValue(rs.getInt(columnName));
        }else if(StringUtils.equals(actualTypeName,Long.class.getName())) {
            t.addDbTypeValue(rs.getLong(columnName));
        }else if(StringUtils.equals(actualTypeName,String.class.getName())) {
            t.addDbTypeValue(rs.getString(columnName));
        }
        return t;
    }

    private String getTypeName() {
        String actualTypeName ="";
        Type[] tp = clazz.getGenericInterfaces();
        for(int i =0;i<tp.length;i++){
            ParameterizedType parameterizedType = (ParameterizedType)tp[i];
            if(StringUtils.contains(parameterizedType.getTypeName(), BaseDbType.class.getName())){
                Type arg = parameterizedType.getActualTypeArguments()[0];
                actualTypeName=arg.getTypeName();
            }
        }
        return actualTypeName;
    }


    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        T t= null;
        try {
            t = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        String actualTypeName = getTypeName();
        if(StringUtils.equals(actualTypeName,Integer.class.getName())){
            t.addDbTypeValue(rs.getInt(columnIndex));
        }else if(StringUtils.equals(actualTypeName,Long.class.getName())) {
            t.addDbTypeValue(rs.getLong(columnIndex));
        }else if(StringUtils.equals(actualTypeName,String.class.getName())) {
            t.addDbTypeValue(rs.getString(columnIndex));
        }
        return t;
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        T t= null;
        try {
            t = clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        String actualTypeName = getTypeName();
        if(StringUtils.equals(actualTypeName,Integer.class.getName())){
            t.addDbTypeValue(cs.getInt(columnIndex));
        }else if(StringUtils.equals(actualTypeName,Long.class.getName())) {
            t.addDbTypeValue(cs.getLong(columnIndex));
        }else if(StringUtils.equals(actualTypeName,String.class.getName())) {
            t.addDbTypeValue(cs.getString(columnIndex));
        }
        return t;
    }
}
